package com.plumecache.core;

import com.plumecache.core.exception.PlumeCacheException;
import lombok.SneakyThrows;
import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.XMemcachedClient;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;

public class MemcachedCacheService extends BaseCacheService {
    private MemcachedClient memcachedClient;

    private static final Integer DEFAULT_EXPIRE_SECOND = 24 * 60 * 60;

    @Override
    public void initialize(InstanceProperties properties) {
        super.initialize(properties);
        try {
            String endpoint = properties.getEndpoint();
            if (StringUtils.isEmpty(endpoint)) {
                throw new PlumeCacheException("can't find [endpoint] properties");
            }

            memcachedClient = new XMemcachedClient(endpoint.split(":")[0], Integer.parseInt(endpoint.split(":")[1]));

            if (StringUtils.isNotBlank(properties.getConnectTimeout())) {
                memcachedClient.setConnectTimeout(Long.parseLong(properties.getConnectTimeout()));
            }

            if (StringUtils.isNotBlank(properties.getConnectionPoolSize())) {
                memcachedClient.setConnectionPoolSize(Integer.parseInt(properties.getConnectTimeout()));
            }
            
        } catch (IOException e) {
            throw new PlumeCacheException(e);
        }
    }

    @Override
    @SneakyThrows
    public <T> void set(String key, T value) {
        memcachedClient.set(key, DEFAULT_EXPIRE_SECOND, serialize(value));
    }

    @Override
    @SneakyThrows
    public <T> void set(String key, T value, Integer ttl) {
        memcachedClient.set(key, ttl, serialize(value));
    }

    @Override
    @SneakyThrows
    public <T> T get(String key, Class<T> clazz) {
        Object value = memcachedClient.get(key);
        return deserialize(String.valueOf(value), clazz);
    }

    @Override
    @SneakyThrows
    public void delete(String key) {
        memcachedClient.delete(key);
    }

    @Override
    @SneakyThrows
    public void expire(String key, Integer ttl) {
        memcachedClient.touch(key, ttl);
    }

    @Override
    public boolean exists(String key) {
        return null != get(key);
    }

    @Override
    @SneakyThrows
    public long incr(String key) {
        return memcachedClient.incr(key, 1);
    }

    @Override
    @SneakyThrows
    public long incrBy(String key, Integer delta) {
        return memcachedClient.incr(key, delta);
    }

    @SneakyThrows
    @Override
    public Map<String, String> getStatistics() {
        Map<InetSocketAddress, Map<String, String>> stats = memcachedClient.getStats();

        if (null == stats || 0 == stats.size()) {
            return Collections.emptyMap();
        }

        Optional<Map.Entry<InetSocketAddress, Map<String, String>>> first = stats.entrySet().stream().findFirst();
        return first.map(Map.Entry::getValue).orElse(null);
    }

    @Override
    public MemcachedClient getMemcachedClient() {
        return memcachedClient;
    }

    @SneakyThrows
    @Override
    public boolean lock(String key, Integer ttl) {
        return memcachedClient.add(key, ttl, "1");
    }

    @Override
    public void release(String key) {
        delete(key);
    }
}
